package com.example.medical.controller;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;

import org.apache.commons.lang.StringUtils;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.example.medical.entity.ApiRequestForMedical;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * @ClassName: ReqThirdCommonController
 * @Description: 调用第三方接口工具类
 * @author lilei474
 * @date 2017年6月20日 下午6:45:57
 * 
 */
@RestController
public class ReqThirdCommonController {

	/**
	 * logger
	 */
	private static final Logger logger = LoggerFactory.getLogger(ReqThirdCommonController.class);

	static ObjectMapper mapper = new ObjectMapper();

	/**
	 * Description: medical模块调用160
	 */
	@RequestMapping("/medical/requestViaFormUrlencoded")
	public String requestViaFormUrlencoded(@RequestBody ApiRequestForMedical apiRequest) {
		String url = apiRequest.getRequestUrl();
		MultiValueMap<String, Object> params = object2LinkedMultiValueMap(apiRequest.getRequestBody());

		String result = postRequestViaFormUrlencoded4Https(url, params);
		return result;
	}

	/**
	 * postRequest for https
	 * 
	 * @param url
	 * @param params
	 * @return
	 */
	public String postRequestViaFormUrlencoded4Https(String url, MultiValueMap<String, ?> params) {
		String respStr = null;
		try {
			RestTemplate restTemplate = getRestTemplate();
			HttpHeaders headers = new HttpHeaders();
			// 设置mediaType为 post form_urlencoded
			headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			HttpEntity<MultiValueMap<String, ?>> req = new HttpEntity<MultiValueMap<String, ?>>(params, headers);
			logger.info("医疗模块调用" + url + "接口入参：" + req.toString());
			ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, req, String.class,
					params);

			if (200 == responseEntity.getStatusCodeValue()) {
				respStr = responseEntity.getBody();
				logger.info("医疗模块调用" + url + "接口返回值：" + respStr);
				return respStr;
			}
		} catch (Exception e) {
			logger.error("医疗模块调用" + url + "接口异常!" + e, e);
		}
		return respStr;
	}

	/**
	 * Description: medical模块调用电商
	 * 
	 * @param apiRequest
	 * @return
	 */
	@RequestMapping("/medical/postRequestForJson")
	public String postRequestViaJsonString4Https(@RequestBody ApiRequestForMedical apiRequest) {
		String result = null;
		try {
			RestTemplate restTemplate = getRestTemplate();
			String url = apiRequest.getRequestUrl();
			String contentType = MediaType.APPLICATION_JSON_VALUE;
			String charset = StringUtils.isBlank(apiRequest.getCharset()) ? "utf-8" : apiRequest.getCharset();

			// 设置mediaType为 post APPLICATION_JSON
			String mediaType = contentType + "; charset=" + charset;
			MediaType type = MediaType.parseMediaType(mediaType);
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(type);
			headers.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);

			String param = mapper.writeValueAsString(apiRequest.getRequestBody());

			HttpEntity<String> formEntity = new HttpEntity<String>(param, headers);
			logger.info("医疗模块调用" + url + "接口入参：" + formEntity);
			result = restTemplate.postForObject(url, formEntity, String.class);
			logger.info("医疗模块调用" + url + "接口返回值：" + result);
		} catch (Exception e) {
			logger.error("post请求异常错误!" + e, e);
		}
		return result;
	}

	/**
	 * @Title: getRequest4Https
	 * @Description: get通用请求
	 * @author lilei474 @date 2017年7月7日 上午11:50:57
	 * @param apiRequest
	 * @return
	 */
	public static String getRequest4Https(@RequestBody ApiRequestForMedical apiRequest) {
		String result = null;
		// ByteArrayOutputStream out = new ByteArrayOutputStream();
		// Map<String, Object> resp = new HashMap<String, Object>();
		// QuYiResponse resp = new QuYiResponse();
		try {

			FormHttpMessageConverter fc = new FormHttpMessageConverter();

			StringHttpMessageConverter m = new StringHttpMessageConverter(Charset.forName("UTF-8"));
			List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();

			messageConverters.add(m);
			messageConverters.add(new ResourceHttpMessageConverter());
			fc.setPartConverters(messageConverters);
			// RestTemplate restTemplate = QuyiSSLClientUtil.getRestTemplate();
			RestTemplate restTemplate = getRestTemplate();
			restTemplate.getMessageConverters().addAll(Arrays.asList(fc, new MappingJackson2HttpMessageConverter()));
			// restTemplate.setMessageConverters(messageConverters);

			String url = apiRequest.getRequestUrl();
			HttpHeaders headers = new HttpHeaders();
			headers.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
			HttpEntity<String> formEntity = new HttpEntity<String>(null, headers);
			logger.info("医疗模块调用" + url);
			logger.info("请求头" + formEntity.toString());
			ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, formEntity, String.class);
			// Set<String> keys = response.getHeaders().keySet();
			// Iterator<String> it = keys.iterator();
			// String values = "";
			// while (it.hasNext()) {
			// String str = it.next();
			// values += str + ": ";
			// List<String> list = response.getHeaders().get(str);
			// for (String s : list) {
			// values += s;
			// }
			// values += ". ";
			//
			// }
			// logger.info("返回请求头" + values);
			// // result = restTemplate.getForObject(url, String.class);

			result = response.getBody();
			// resp = mapper.readValue(result, Map.class);

			// return resp;
			// logger.info("医疗模块调用" + url + "接口返回值：" + result);
			// logger.info("医疗模块调用" + url + "接口JACKSON转化后的返回值：" +
			// JacksonTools.toJSonString(result));
		} catch (Exception e) {
			logger.error("get请求异常错误!" + e, e);
		}
		// return result;
		return result;
	}

	public static void main(String[] args) {
		ApiRequestForMedical apiRequest = new ApiRequestForMedical();
		// 淘宝获取手机号归属地接口
		String url = "https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=18861986320";
		apiRequest.setRequestUrl(url);
		String retval = getRequest4Https(apiRequest);
		System.out.println(retval);
	}

	/**
	 * @Title: getRestTemplate
	 * @Description: 获取RestTemplate实例
	 * @author LILEI474 @date 2017年7月18日 下午4:36:02
	 * @return
	 * @throws KeyManagementException
	 * @throws KeyStoreException
	 * @throws NoSuchAlgorithmException
	 */
	private static RestTemplate getRestTemplate()
			throws KeyManagementException, KeyStoreException, NoSuchAlgorithmException {
		// 提供对https的支持
		CloseableHttpClient httpClient = HttpClientUtils.acceptsUntrustedCertsHttpClient();
		HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(
				httpClient);
		// 设置连接超时和读超时时间
		clientHttpRequestFactory.setConnectTimeout(3000);
		clientHttpRequestFactory.setReadTimeout(30000);
		return new RestTemplate(clientHttpRequestFactory);
	}

	/**
	 * @Title: object2LinkedMultiValueMap
	 * @Description: 对象转为LinkedMultiValueMap
	 * @author lilei474 @date 2017年7月7日 上午11:51:54
	 * @param param
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static MultiValueMap<String, Object> object2LinkedMultiValueMap(Object param) {
		MultiValueMap<String, Object> params = new LinkedMultiValueMap<String, Object>();

		if (param instanceof Map) {
			Iterator<Entry<String, Object>> iterator = ((Map<String, Object>) param).entrySet().iterator();
			while (iterator.hasNext()) {
				Entry<String, Object> entry = iterator.next();
				params.add(entry.getKey(), entry.getValue());
			}
		} else {
			Field[] field = param.getClass().getDeclaredFields(); // 获取实体类的所有属性，返回Field数组
			for (Field f : field) {
				if (!StringUtils.equals(f.getName(), "serialVersionUID")) {
					params.add(f.getName(), getFieldValueByName(f.getName(), param));
				}
			}
		}
		return params;
	}

	/**
	 * 根据属性名获取属性值
	 */
	private static Object getFieldValueByName(String fieldName, Object o) {
		try {
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			String getter = "get" + firstLetter + fieldName.substring(1);
			Method method = o.getClass().getMethod(getter, new Class[] {});
			Object value = method.invoke(o, new Object[] {});
			return value;
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return null;
		}
	}
}

class HttpClientUtils {
	public static CloseableHttpClient acceptsUntrustedCertsHttpClient()
			throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
		HttpClientBuilder b = HttpClientBuilder.create();
		// setup a Trust Strategy that allows all certificates.
		SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
			public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
				return true;
			}
		}).build();
		b.setSSLContext(sslContext);
		// don't check Hostnames, either.
		// -- use SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if
		// you don't want to weaken
		HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
		// here's the special part:
		// -- need to create an SSL Socket Factory, to use our weakened "trust
		// strategy";
		// -- and create a Registry, to register it.
		SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
		Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
				.register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslSocketFactory)
				.build();
		// now, we create connection-manager using our Registry.
		// -- allows multi-threaded use
		PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
		connMgr.setMaxTotal(200);
		connMgr.setDefaultMaxPerRoute(100);
		b.setConnectionManager(connMgr);
		// finally, build the HttpClient;
		// -- done!
		CloseableHttpClient client = b.build();
		return client;
	}
}
